package org.iks.push.handler;

import cn.hutool.core.util.StrUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.Attribute;
import lombok.extern.slf4j.Slf4j;
import org.iks.common.util.IpUtil;
import org.iks.common.util.JwtUtil;
import org.iks.push.config.RedisCacheUtil;
import org.iks.push.constant.ChannelConstant;
import org.iks.push.message.AuthVerifyMessage;
import org.iks.push.session.SessionManage;
import org.iks.push.business.vo.OnlineUserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @author kzou
 * @date 2024/1/3 11:18
 * @description: 用户ws认证
 */
@ChannelHandler.Sharable
@Slf4j
@Component
public class AuthVerifyHandler extends SimpleChannelInboundHandler<AuthVerifyMessage> {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Value("${netty.ws.port}")
    private Integer port;

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, AuthVerifyMessage authVerifyMessage) throws Exception {
        Channel channel = channelHandlerContext.channel();

        // token 解析校验
        String token = authVerifyMessage.getToken();
        String publicKey = JwtUtil.tryGetPublicKey(token);
        String account = JwtUtil.tryGetUserAccount(token);
        if (!JwtUtil.isValid(token) || StrUtil.isEmpty(publicKey) || StrUtil.isEmpty(account)) {
            log.warn("reject invalid ws connection");
            channel.close();
            return;
        }

        // 认证完成，邦定用户公钥
        channel.attr(ChannelConstant.getPublicAddressAttrKey()).set(publicKey);
        channel.attr(ChannelConstant.getAccountAttrKey()).set(account);


        // 写入 redis
        String ipAddress = IpUtil.tryGetLocalIpAddress();
        if (ipAddress != null) {
            OnlineUserVo userVo = new OnlineUserVo(account, ipAddress + ":" + port, new Date(), "");
            RedisCacheUtil.storeUser(userVo);
        }

        SessionManage.addChannel(channel);
        super.channelActive(channelHandlerContext);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Attribute<String> account = ctx.channel().attr(ChannelConstant.getAccountAttrKey());
        if (account != null && account.get() != null) {
            RedisCacheUtil.deleteUser(account.get());
            log.info("{} user offline", account.get());
        }
        super.channelInactive(ctx);
    }

}
